﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace System
{
	public delegate bool PermutationResultEvent(Permutator p);

	public abstract class PermutationStep
	{
		public abstract PermutationStep Reverse();
	}
	public enum PermutationResult
	{
		Failed,
		Passed,
		Finished
	}
	public abstract class Permutator
	{
		public abstract void ResetState();

		public Permutator()
		{
		}
		public void StartSearch()
		{
			ResetState();
			int CurrentStack = StepStack.Count;
			ProcessAbort = false;
			Process(0);
		}

		protected abstract PermutationResult CheckTable(int CurrentDepth);
		bool ProcessAbort = false;

		public event Action<int> ondepth;
		void Process(int Depth)
		{
			List<PermutationStep> Steps = GetValidSteps(Depth);
			for (int i = 0; !ProcessAbort && i < Steps.Count; i++)
			{
				AddStep(Steps[i]);
				PermutationResult Res = CheckTable(Depth);
				if (Res == PermutationResult.Finished)
				{
					if (!ProcessResult())
						ProcessAbort = true;
				}
				else if (Res == PermutationResult.Passed)
				{
					Process(Depth + 1);
				}
				RevertLastStep();
			}
		}
		public event PermutationResultEvent OnResult;
		protected virtual bool ProcessResult()
		{
			return OnResult(this);
		}
		public Stack<PermutationStep> StepStack = new Stack<PermutationStep>();

		void AddStep(PermutationStep istep)
		{
			StepStack.Push(istep);
			ApplyStep(istep);
		}
		protected virtual void ApplyStep(PermutationStep istep)
		{
		}

		void RevertLastStep()
		{
			PermutationStep last = StepStack.Pop().Reverse();
			ApplyStep(last);
		}
		public abstract List<PermutationStep> GetValidSteps(int depth);
	}
}